import random
import re
import time

from django.core.cache import cache
from django.shortcuts import render


from rest_framework.views import APIView
from rest_framework.response import Response

from django.contrib.auth import authenticate
from rest_framework_simplejwt.tokens import RefreshToken

from login.models import User

import logging
logging = logging.getLogger('django')
# Create your views here.



class LoginView(APIView):
    # 一定是post请求！
    def post(self,request):
        try:
            # 1.先获取前端传过来的用户名和密码
            username = request.data.get('username')
            password = request.data.get('password')
            # 2.验证参数是否为空
            if not all(['username','password']):   # 同时验证：all方法+not = 所有都没有
                # 没有数据的话(为空)，我要进行响应提示
                logging.error('用户名或密码不能为空')
                return Response({
                    'code':0,
                    'msg':'用户名或密码不能为空'
                })
            # 3.如果写了东西，验证用户名和密码的正确性
            # user只是一个验证结果的实例化对象，authenticate是自带的验证方法拿来用，username和password是验证的固定参数
            user = authenticate(username=username,password=password)
            if not user:
                # 4.意味着验证失败，返回错误信息
                logging.error('用户名或密码错误')
                return Response({
                    'code':0,
                    'msg':'用户名或密码错误'
                })

            # 5.反之，验证成功，要给一个令牌(唯一标识)返回给前端
            # 生成token令牌的语法
            refresh = RefreshToken.for_user(user)  # 这里的user是验证成功的user实例化对象，给他生成令牌
            # 生成访问token:access token ；延期刷新token：refresh token
            logging.info(f'{username}用户登陆成功')
            return Response({
                'code':1,
                'msg':'登陆成功',
                'data':{
                    'token':str(refresh.access_token),
                    'refresh':str(refresh),  # 因为refresh用的是refresh的模型方法，里面自带str方法，直接返回refresh对象就行
                    'username':username,
                    'user_id':user.id
                }
            })

        except Exception as e:
            logging.error('登陆失败')
            return Response({
                'code':0,
                'msg':f'登陆失败,错误信息为{e}'
            })





class SendMsgAPIView(APIView):
    def post(self,request):
        try:
            phone = request.data.get('phone')
            scene = request.data.get('scene','login')  # 设置默认值-->默认不传的话就为已登录
            ret = re.match(r"^1[3-9]\d{9}$",phone)
            if not ret:
                logging.error('手机号格式不正确')
                return Response({
                    'code':0,
                    'msg':'手机号格式不正确'
                })


            # 判断场景-->
            # 1.注册场景：手机号未注册，查不到的才醒
            # 2.登陆场景：手机号注册过，能查到才行
            if scene == 'login':
                # 验证手机号是否注册过
                phone_user = User.objects.filter(phone=phone)
                if not phone_user.exists():
                    logging.error('手机号未注册')
                    return Response({
                        'code':0,
                        'msg':'手机号未注册'
                    })
            elif scene == 'register':
                phone_user = User.objects.filter(phone=phone)
                if phone_user.exists():
                    logging.error('手机号已注册')
                    return Response({
                        'code': 0,
                        'msg': '手机号已注册'
                    })

            # 验证码这里是通用的
            # 生成验证码前记录时间-->如果他发送过怎么办
            before_time_key = f'login:time:{phone}'
            before_time = cache.get(before_time_key)
            now = time.time()
            # 同时判断-->是否有上次生成/生成是否过冷却期
            if before_time and now-before_time < 60:
                logging.error('60秒还没完')
                return Response({
                    'code':0,
                    'msg':f'请勿频繁发送,在{60-(now-before_time)}秒后重试'
                })
            # 可以生成了
            random_code = str(random.randint(1000,9999))
            random_code_key = f'login:code:{phone}'
            logging.info(random_code)
            cache.set(random_code_key,random_code,timeout=60*5)

            # 更新生成时间
            cache.set(before_time_key, now, timeout=60)

            # 生成后别忘记发送啊
            logging.info(f'{phone}用户您的验证码是{random_code}')
            return Response({
                'code':1,
                'msg':'验证码发送成功'
            })


        except Exception as e:
            logging.error(f'验证码发送失败{e}')
            return Response({
                'code':0,
                'msg':f'验证码发送失败,错误信息为{e}'
            })





class SentLoginAPIView(APIView):
    def post(self,request):
        try:
            phone = request.data.get('phone','')
            code = request.data.get('code','')
            logging.info(code,phone)
            ret = re.match(r'^1[3-9]\d{9}$',phone)
            if not ret:
                logging.error('手机号格式不正确')
                return Response({
                    'code':0,
                    'msg':'手机号格式不正确'
                })

            if not User.objects.filter(phone=phone).exists():
                logging.error('手机号未注册')
                return Response({
                    'code':0,
                    'msg':'手机号未注册'
                })


            # 验证验证码
            # 先找到自己缓存里的再进行比较
            random_code_key = f'login:code:{phone}'
            redis_code = cache.get(random_code_key)
            if not redis_code:
                logging.error('验证码过期')
                return Response({
                    'code':0,
                    'msg':'验证码过期'
                })

            if code != redis_code:
                logging.error('验证码错误')
                return Response({
                    'code':0,
                    'msg':'验证码错误'
                })

            # 验证成功就要清理这个验证码
            cache.delete(random_code_key)


            # 生成token
            user = User.objects.get(phone=phone)
            refresh = RefreshToken.for_user(user)
            logging.info(f"{phone}用户登录成功")
            return Response({
                'code':1,
                'msg':'登录成功',
                'data':{
                    'token':str(refresh.access_token),
                    'refresh':str(refresh),
                    'username':user.username,
                    'user_id':user.id
                }
            })

        except Exception as e:
            logging.error('登录失败')
            return Response({
                'code':0,
                'msg':f'登录失败,错误信息为{e}'
            })




# 注册接口：
class RegisterAPIView(APIView):
    def post(self,request):
        try:
            # 1.接收参数
            username = request.data.get('username')
            password = request.data.get('password')
            phone = request.data.get('phone')
            code = request.data.get('code')
            # 验证非空
            if not all([username,password,phone,code]):
                return Response({
                    'code':0,
                    'msg':"用户名或密码不能为空"
                })

            ret = re.match(r"^1[3-9]\d{9}$",phone)
            if not ret:
                return Response({
                    'code':0,
                    'msg':"手机号格式不正确"
                })

            if User.objects.filter(phone=phone).exists():
                return Response({
                    'code':0,
                    'msg':"手机号已注册"
                })

            # 判断验证码
            random_code_key = f'login:code:{phone}'
            redis_code = cache.get(random_code_key)
            print(redis_code,code)

            if redis_code != code:
                return Response({
                    'code':0,
                    'msg':'验证码错误'
                })

            # 如果都符合，注册成功写入表中
            new_user = User.objects.create_user(username=username,password=password,phone=phone)
            cache.delete(random_code_key)
            refresh = RefreshToken.for_user(new_user)
            return Response({
                'code':1,
                'msg':'注册成功',
                'data':{
                    'token':str(refresh.access_token),
                    'username':new_user.username,
                    'user_id':new_user.id,
                    'refresh_token':str(refresh)

            }
            })
        except Exception as e:
            logging.error('注册失败')
            return Response({
                'code':0,
                'msg':f"注册失败，错误信息为{e}"
            })
